#include <stdio.h>
#include <string.h>
#include <scos.h>
#include <log.h>

#include <scu.h>

#define COPY
#define READERS   4
#define UNITS     10000
#define UNIT_SIZE 65535
#define BUFUNITS  100

scu_buf_t buf;
int running[READERS];
static log_default_streams_t blg;

void *writer(void*);
void *reader(void*);

int MAIN(void)
{
  int i, init;
  scos_thread_t w, r[READERS];

#ifndef LIBDYNAMIC
  //liblog_init();
  _scuInit();
#endif

  blg = logGetDefaultStreams();
  logEdit(blg.crawl, LOG_GROUP_SET_LEVEL);
  logRegisterThread("main");
  
  memset(running, 0, READERS*sizeof(int));

  buf = scuBufferCreate(UNIT_SIZE*BUFUNITS, SCU_BUF_MAX_READERS, NULL);

  scos_thread_create_joinable(&w, writer, NULL);
  for (i=0; i < READERS; i++)
    scos_thread_create_joinable(&r[i], reader, (void*)i);

  lprintf(STREAM(blg.info), "Waiting for threads to start");

  do
  {
    init = 1;
    for (i=0; i < READERS; i++)
      init = init * running[i];
	sched_yield();
  } while (!init);  

  lprintf(STREAM(blg.info), "Running test");

  scuBufferUnlock(&buf);
  
  scos_thread_join(&w);
  for (i=0; i < READERS; i++)
    scos_thread_join(&r[i]);

  return 0;
}

void *writer(void* dummy)
{
  char data[UNIT_SIZE];
#ifndef COPY
  char *ptrdata;
#endif  
  int i, b;

  logRegisterThread("writer");
  lprintf(STREAM(blg.notice), "Writer started");

  for (i=0; i < UNITS; i++)
  {
#ifdef COPY
    for (b=0; b < UNIT_SIZE; b++) data[b] = b;
    scuBufferWrite(&buf, data, UNIT_SIZE, SCU_BUF_BLOCK_ALL);
#else
    scuBufferAllocate(&buf, (void**)&ptrdata, UNIT_SIZE, SCU_BUF_BLOCK_ALL);
    for (b=0; b < UNIT_SIZE; b++) ptrdata[b] = b;
    scuBufferReleaseAllocated(&buf, UNIT_SIZE);
#endif
    //usleep(1000000L);
  }

  return NULL;
}

void *reader(void* id)
{
  char data[UNIT_SIZE];
#ifndef COPY
  char *ptrdata;
#endif
  scu_bufptrid_t r;
  int i, b;
  tmr_t timer = tmrInit();
  
  sprintf(data, "reader%03d", (int)id);
  logRegisterThread(data);
  lprintf(STREAM(blg.notice), "Reader %d started", (int)id);

  r = scuBufferAddReader(&buf);

  running[(int)id] = 1;
  
  tmrStart(&timer);
  for (i=0; i < UNITS; i++)
  {
    //printf("reader %d iteration %d\n", (int)id, i++);
    //printf("read %d bytes\n", scuBufferRead(&buf, r, data, 512, SCU_BUF_BLOCK));
#ifdef COPY
    scuBufferRead(&buf, r, data, UNIT_SIZE, SCU_BUF_BLOCK_ALL);
    for (b=0; b < UNIT_SIZE; b++) data[b] = data[b]+1;
#else
    scuBufferPeek(&buf, r, (void**)&ptrdata, UNIT_SIZE, SCU_BUF_BLOCK_ALL);
    for (b=0; b < UNIT_SIZE; b++) ptrdata[b] = ptrdata[b]+1;
    scuBufferReleasePeeked(&buf, r, UNIT_SIZE);
#endif
    //usleep(1000000L);
  }
  tmrStop(&timer);

  printf("Speed was %f MB/s\n", (double)UNITS*UNIT_SIZE/tmrGetValueInUs(&timer));
 
  return NULL;
}
